#include "common/elements/role.h"

#include "common/log/log.h"

#include "data_role.h"

namespace Database
{

DataRole::DataRole(Elements::Element* element)
{
    setElement(element);
}

DataRole::DataRole(std::shared_ptr<Elements::Element> element)
{
    m_element = element;
}

DataRole::DataRole(sqlite::database& database, unsigned id)
{
    fromDatabase(database, id);
}

DataElement* DataRole::clone() const
{
    if (m_element)
        return new DataRole(m_element->clone());

    return nullptr;
}

DataElement* DataRole::wrap(Elements::Element* element) const
{
    return new DataRole(element);
}

void DataRole::toDatabase(sqlite::database& database)
{
    const auto element = std::dynamic_pointer_cast<Elements::Role>(m_element);
    if (nullptr == element)
        return;

    if (0 == element->id())
    {
        const auto sqlStr = "INSERT INTO Role "
                            "( caption "
                            ", description "
                            ", basePermissions "
                            ") VALUES (?,?,?);";
        database
            << sqlStr
            << element->caption()
            << element->description()
            << unsigned(element->basePermissions());
        element->setId(lastAddedId(database));
        return;
    }

    const auto sqlStr = "INSERT OR REPLACE INTO Role "
                        "( id "
                        ", caption "
                        ", description "
                        ", basePermissions "
                        ") VALUES (?,?,?,?);";
    database
        << sqlStr
        << element->id()
        << element->caption()
        << element->description()
        << unsigned(element->basePermissions());
}

void DataRole::fromDatabase(sqlite::database& database, unsigned id)
{
    if (nullptr == m_element)
        m_element.reset(new Elements::Role());

    const auto element = std::dynamic_pointer_cast<Elements::Role>(m_element);

    const auto sqlStr = "SELECT "
                        "  id "
                        ", caption "
                        ", description "
                        ", basePermissions "
                        "FROM Role WHERE id = ?;";
    database << sqlStr << id >>
        [element](
            unsigned id,
            std::string caption,
            std::string description,
            unsigned basePermissions
        )
    {
        element->setId(id);
        element->setCaption(caption);
        element->setDescription(description);
        element->setBasePermissions(basePermissions);
    };
}

std::vector<Elements::Element*> DataRole::fromDatabaseElements(
    sqlite::database& database,
    std::vector<unsigned> ids
) const
{
    const auto sqlStr = "SELECT "
                        "  id "
                        ", caption "
                        ", description "
                        ", basePermissions "
                        "FROM Role WHERE id in ("
        + questionMarks(ids.size())
        + ")";

    auto query = database << sqlStr;
    for (auto id : ids)
        query << id;

    std::vector<Elements::Element*> result;
    query >>
        [&result](
            unsigned id,
            std::string caption,
            std::string description,
            unsigned basePermissions
        )
    {
        auto element = new Elements::Role();
        element->setId(id);
        element->setCaption(caption);
        element->setDescription(description);
        element->setBasePermissions(basePermissions);
        result.push_back(element);
    };
    return result;
}

// Получение идентификаторов ---------------------------------------------------

std::vector<unsigned> DataRole::ids(
    sqlite::database& database
)
{
    std::vector<unsigned> result;
    database << "SELECT id FROM Role;"
        >> [&result](unsigned id)
    {
        result.emplace_back(id);
    };
    return result;
}

// Удаление --------------------------------------------------------------------

void DataRole::removeOne(
    sqlite::database& database,
    unsigned id
)
{
    std::vector<unsigned> ids = { id };
    remove(database, ids);
}

void DataRole::remove(
    sqlite::database& database,
    std::vector<unsigned> ids
)
{
    const auto sqlStr = "DELETE FROM Role WHERE id in ("
        + questionMarks(ids.size())
        + ")";

    auto query = database << sqlStr;
    for (auto id : ids)
        query << id;

    query.execute();
    query.reset();
}

} // namespace Elements
